home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / gui / x / twm93053.lha / twm / events.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-30  |  76.7 KB  |  2,860 lines

  1. /*****************************************************************************/
  2. /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
  3. /**                          Salt Lake City, Utah                           **/
  4. /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
  5. /**                        Cambridge, Massachusetts                         **/
  6. /**                                                                         **/
  7. /**                           All Rights Reserved                           **/
  8. /**                                                                         **/
  9. /**    Permission to use, copy, modify, and distribute this software and    **/
  10. /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
  11. /**    granted, provided that the above copyright notice appear  in  all    **/
  12. /**    copies and that both  that  copyright  notice  and  this  permis-    **/
  13. /**    sion  notice appear in supporting  documentation,  and  that  the    **/
  14. /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
  15. /**    in publicity pertaining to distribution of the  software  without    **/
  16. /**    specific, written prior permission.                                  **/
  17. /**                                                                         **/
  18. /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
  19. /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
  20. /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
  21. /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
  22. /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
  23. /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
  24. /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
  25. /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
  26. /*****************************************************************************/
  27.  
  28.  
  29. /***********************************************************************
  30.  *
  31.  * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
  32.  *
  33.  * twm event handling
  34.  *
  35.  * 17-Nov-87 Thomas E. LaStrange        File created
  36.  *
  37.  ***********************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include "twm.h"
  41. #include <X11/Xatom.h>
  42. #include "add_window.h"
  43. #include "menus.h"
  44. #include "events.h"
  45. #include "resize.h"
  46. #include "parse.h"
  47. #include "gram.h"
  48. #include "util.h"
  49. #include "screen.h"
  50. #include "iconmgr.h"
  51. #include "version.h"
  52.  
  53. extern int iconifybox_width, iconifybox_height;
  54. extern unsigned int mods_used;
  55. extern int menuFromFrameOrWindowOrTitlebar;
  56.  
  57. #define MAX_X_EVENT 256
  58. event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
  59. char *Action;
  60. int Context = C_NO_CONTEXT;    /* current button press context */
  61. TwmWindow *ButtonWindow;    /* button press window structure */
  62. XEvent ButtonEvent;        /* button press event */
  63. XEvent Event;            /* the current event */
  64. TwmWindow *Tmp_win;        /* the current twm window */
  65.  
  66. /* Used in HandleEnterNotify to remove border highlight from a window 
  67.  * that has not recieved a LeaveNotify event because of a pointer grab 
  68.  */
  69. TwmWindow *UnHighLight_win = NULL;
  70.  
  71. Window DragWindow;        /* variables used in moving windows */
  72. int origDragX;
  73. int origDragY;
  74. int DragX;
  75. int DragY;
  76. int DragWidth;
  77. int DragHeight;
  78. int CurrentDragX;
  79. int CurrentDragY;
  80.  
  81. /* Vars to tell if the resize has moved. */
  82. extern int ResizeOrigX;
  83. extern int ResizeOrigY;
  84.  
  85. static int enter_flag;
  86. static int ColortableThrashing;
  87. static TwmWindow *enter_win, *raise_win;
  88.  
  89. ScreenInfo *FindScreenInfo();
  90. int ButtonPressed = -1;
  91. int Cancel = FALSE;
  92.  
  93. void HandleCreateNotify();
  94.  
  95. void HandleShapeNotify ();
  96. extern int ShapeEventBase, ShapeErrorBase;
  97.  
  98. void AutoRaiseWindow (tmp)
  99.     TwmWindow *tmp;
  100. {
  101.     XRaiseWindow (dpy, tmp->frame);
  102.     XSync (dpy, 0);
  103.     enter_win = NULL;
  104.     enter_flag = TRUE;
  105.     raise_win = tmp;
  106. }
  107.  
  108. void SetRaiseWindow (tmp)
  109.     TwmWindow *tmp;
  110. {
  111.     enter_flag = TRUE;
  112.     enter_win = NULL;
  113.     raise_win = tmp;
  114.     XSync (dpy, 0);
  115. }
  116.  
  117.  
  118.  
  119. /***********************************************************************
  120.  *
  121.  *  Procedure:
  122.  *    InitEvents - initialize the event jump table
  123.  *
  124.  ***********************************************************************
  125.  */
  126.  
  127. void
  128. InitEvents()
  129. {
  130.     int i;
  131.  
  132. #ifdef DEBUG_EVENTS
  133.     printf("InitEvents()\n");
  134. #endif
  135.  
  136.     ResizeWindow = NULL;
  137.     DragWindow = NULL;
  138.     enter_flag = FALSE;
  139.     enter_win = raise_win = NULL;
  140.  
  141.     for (i = 0; i < MAX_X_EVENT; i++)
  142.     EventHandler[i] = HandleUnknown;
  143.  
  144.     EventHandler[Expose] = HandleExpose;
  145.     EventHandler[CreateNotify] = HandleCreateNotify;
  146.     EventHandler[DestroyNotify] = HandleDestroyNotify;
  147.     EventHandler[MapRequest] = HandleMapRequest;
  148.     EventHandler[MapNotify] = HandleMapNotify;
  149.     EventHandler[UnmapNotify] = HandleUnmapNotify;
  150.     EventHandler[MotionNotify] = HandleMotionNotify;
  151.     EventHandler[ButtonRelease] = HandleButtonRelease;
  152.     EventHandler[ButtonPress] = HandleButtonPress;
  153.     EventHandler[EnterNotify] = HandleEnterNotify;
  154.     EventHandler[LeaveNotify] = HandleLeaveNotify;
  155.     EventHandler[ConfigureRequest] = HandleConfigureRequest;
  156.     EventHandler[ClientMessage] = HandleClientMessage;
  157.     EventHandler[PropertyNotify] = HandlePropertyNotify;
  158.     EventHandler[KeyPress] = HandleKeyPress;
  159.     EventHandler[ColormapNotify] = HandleColormapNotify;
  160.     EventHandler[VisibilityNotify] = HandleVisibilityNotify;
  161.     if (HasShape)
  162.     EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
  163. }
  164.  
  165.  
  166.  
  167.  
  168. Time lastTimestamp = CurrentTime;    /* until Xlib does this for us */
  169.  
  170. Bool StashEventTime (ev)
  171.     register XEvent *ev;
  172. {
  173. #ifdef DEBUG_EVENTS
  174.     printf("StashEventTime()\n");
  175. #endif
  176.     switch (ev->type) {
  177.       case KeyPress:
  178.       case KeyRelease:
  179.     lastTimestamp = ev->xkey.time;
  180.     return True;
  181.       case ButtonPress:
  182.       case ButtonRelease:
  183.     lastTimestamp = ev->xbutton.time;
  184.     return True;
  185.       case MotionNotify:
  186.     lastTimestamp = ev->xmotion.time;
  187.     return True;
  188.       case EnterNotify:
  189.       case LeaveNotify:
  190.     lastTimestamp = ev->xcrossing.time;
  191.     return True;
  192.       case PropertyNotify:
  193.     lastTimestamp = ev->xproperty.time;
  194.     return True;
  195.       case SelectionClear:
  196.     lastTimestamp = ev->xselectionclear.time;
  197.     return True;
  198.       case SelectionRequest:
  199.     lastTimestamp = ev->xselectionrequest.time;
  200.     return True;
  201.       case SelectionNotify:
  202.     lastTimestamp = ev->xselection.time;
  203.     return True;
  204.     }
  205.     return False;
  206. }
  207.  
  208.  
  209.  
  210. /*
  211.  * WindowOfEvent - return the window about which this event is concerned; this
  212.  * window may not be the same as XEvent.xany.window (the first window listed
  213.  * in the structure).
  214.  */
  215. Window WindowOfEvent (e)
  216.     XEvent *e;
  217. {
  218. #ifdef DEBUG_EVENTS
  219.     printf("WindowOfEvent()\n");
  220. #endif
  221.     /*
  222.      * Each window subfield is marked with whether or not it is the same as
  223.      * XEvent.xany.window or is different (which is the case for some of the
  224.      * notify events).
  225.      */
  226.     switch (e->type) {
  227.       case KeyPress:
  228.       case KeyRelease:  return e->xkey.window;                 /* same */
  229.       case ButtonPress:
  230.       case ButtonRelease:  return e->xbutton.window;             /* same */
  231.       case MotionNotify:  return e->xmotion.window;             /* same */
  232.       case EnterNotify:
  233.       case LeaveNotify:  return e->xcrossing.window;             /* same */
  234.       case FocusIn:
  235.       case FocusOut:  return e->xfocus.window;                 /* same */
  236.       case KeymapNotify:  return e->xkeymap.window;             /* same */
  237.       case Expose:  return e->xexpose.window;                 /* same */
  238.       case GraphicsExpose:  return e->xgraphicsexpose.drawable;         /* same */
  239.       case NoExpose:  return e->xnoexpose.drawable;             /* same */
  240.       case VisibilityNotify:  return e->xvisibility.window;         /* same */
  241.       case CreateNotify:  return e->xcreatewindow.window;         /* DIFF */
  242.       case DestroyNotify:  return e->xdestroywindow.window;         /* DIFF */
  243.       case UnmapNotify:  return e->xunmap.window;             /* DIFF */
  244.       case MapNotify:  return e->xmap.window;                 /* DIFF */
  245.       case MapRequest:  return e->xmaprequest.window;             /* DIFF */
  246.       case ReparentNotify:  return e->xreparent.window;             /* DIFF */
  247.       case ConfigureNotify:  return e->xconfigure.window;         /* DIFF */
  248.       case ConfigureRequest:  return e->xconfigurerequest.window;    /* DIFF */
  249.       case GravityNotify:  return e->xgravity.window;             /* DIFF */
  250.       case ResizeRequest:  return e->xresizerequest.window;         /* same */
  251.       case CirculateNotify:  return e->xcirculate.window;         /* DIFF */
  252.       case CirculateRequest:  return e->xcirculaterequest.window;    /* DIFF */
  253.       case PropertyNotify:  return e->xproperty.window;             /* same */
  254.       case SelectionClear:  return e->xselectionclear.window;         /* same */
  255.       case SelectionRequest: return e->xselectionrequest.requestor;  /* DIFF */
  256.       case SelectionNotify:  return e->xselection.requestor;         /* same */
  257.       case ColormapNotify:  return e->xcolormap.window;             /* same */
  258.       case ClientMessage:  return e->xclient.window;             /* same */
  259.       case MappingNotify:  return None;
  260.     }
  261.     return None;
  262. }
  263.  
  264.  
  265.  
  266. /***********************************************************************
  267.  *
  268.  *  Procedure:
  269.  *    DispatchEvent2 - 
  270.  *      handle a single X event stored in global var Event
  271.  *      this rouitine for is for a call during an f.move
  272.  *
  273.  ***********************************************************************
  274.  */
  275. Bool DispatchEvent2 ()
  276. {
  277.     Window w = Event.xany.window;
  278. #ifdef DEBUG_EVENTS
  279.     printf("DispatchEvent2()\n");
  280. #endif
  281.     StashEventTime (&Event);
  282.  
  283.     if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
  284.       Tmp_win = NULL;
  285.  
  286.     if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
  287.     Scr = FindScreenInfo (WindowOfEvent (&Event));
  288.     }
  289.  
  290.     if (!Scr) return False;
  291.  
  292.     if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
  293.       HandleExpose();
  294.  
  295.     if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
  296.     (*EventHandler[Event.type])();
  297.     }
  298.  
  299.     return True;
  300. }
  301.  
  302. /***********************************************************************
  303.  *
  304.  *  Procedure:
  305.  *    DispatchEvent - handle a single X event stored in global var Event
  306.  *
  307.  ***********************************************************************
  308.  */
  309. Bool DispatchEvent ()
  310. {
  311.     Window w = Event.xany.window;
  312. #ifdef DEBUG_EVENTS
  313.     printf("DispatchEvent()\n");
  314. #endif
  315.     StashEventTime (&Event);
  316.  
  317.     if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
  318.       Tmp_win = NULL;
  319.  
  320.     if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
  321.     Scr = FindScreenInfo (WindowOfEvent (&Event));
  322.     }
  323.  
  324.     if (!Scr) return False;
  325.  
  326.     if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
  327.     (*EventHandler[Event.type])();
  328.     }
  329.  
  330.     return True;
  331. }
  332.  
  333.  
  334.  
  335. /***********************************************************************
  336.  *
  337.  *  Procedure:
  338.  *    HandleEvents - handle X events
  339.  *
  340.  ***********************************************************************
  341.  */
  342.  
  343. void
  344. HandleEvents()
  345. {
  346. #ifdef DEBUG_EVENTS
  347.     printf("HandleEvents()\n");
  348. #endif
  349.     while (TRUE)
  350.     {
  351.     if (enter_flag && !QLength(dpy)) {
  352.         if (enter_win && enter_win != raise_win) {
  353.         AutoRaiseWindow (enter_win);  /* sets enter_flag T */
  354.         } else {
  355.         enter_flag = FALSE;
  356.         }
  357.     }
  358.     if (ColortableThrashing && !QLength(dpy) && Scr) {
  359.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  360.     }
  361.     WindowMoved = FALSE;
  362.     XNextEvent(dpy, &Event);
  363.     (void) DispatchEvent ();
  364.     }
  365. }
  366.  
  367.  
  368.  
  369. /***********************************************************************
  370.  *
  371.  *  Procedure:
  372.  *    HandleColormapNotify - colormap notify event handler
  373.  *
  374.  * This procedure handles both a client changing its own colormap, and
  375.  * a client explicitly installing its colormap itself (only the window
  376.  * manager should do that, so we must set it correctly).
  377.  *
  378.  ***********************************************************************
  379.  */
  380.  
  381. void
  382. HandleColormapNotify()
  383. {
  384.     XColormapEvent *cevent = (XColormapEvent *) &Event;
  385.     ColormapWindow *cwin, **cwins;
  386.     TwmColormap *cmap;
  387.     int lost, won, n, number_cwins;
  388.     extern TwmColormap *CreateTwmColormap();
  389.  
  390. #ifdef DEBUG_EVENTS
  391.     printf("HandleColormapNotify()\n");
  392. #endif
  393.     if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
  394.     return;
  395.     cmap = cwin->colormap;
  396.  
  397.     if (cevent->new)
  398.     {
  399.     if (XFindContext(dpy, cevent->colormap, ColormapContext,
  400.              (caddr_t *)&cwin->colormap) == XCNOENT)
  401.         cwin->colormap = CreateTwmColormap(cevent->colormap);
  402.     else
  403.         cwin->colormap->refcnt++;
  404.  
  405.     cmap->refcnt--;
  406.  
  407.     if (cevent->state == ColormapUninstalled)
  408.         cmap->state &= ~CM_INSTALLED;
  409.     else
  410.         cmap->state |= CM_INSTALLED;
  411.  
  412.     if (cmap->state & CM_INSTALLABLE)
  413.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  414.  
  415.     if (cmap->refcnt == 0)
  416.     {
  417.         XDeleteContext(dpy, cmap->c, ColormapContext);
  418.         free((char *) cmap);
  419.     }
  420.  
  421.     return;
  422.     }
  423.  
  424.     if (cevent->state == ColormapUninstalled &&
  425.     (cmap->state & CM_INSTALLABLE))
  426.     {
  427.     if (!(cmap->state & CM_INSTALLED))
  428.         return;
  429.     cmap->state &= ~CM_INSTALLED;
  430.  
  431.     if (!ColortableThrashing)
  432.     {
  433.         ColortableThrashing = TRUE;
  434.         XSync(dpy, 0);
  435.     }
  436.  
  437.     if (cevent->serial >= Scr->cmapInfo.first_req)
  438.     {
  439.         number_cwins = Scr->cmapInfo.cmaps->number_cwins;
  440.  
  441.         /*
  442.          * Find out which colortables collided.
  443.          */
  444.  
  445.         cwins = Scr->cmapInfo.cmaps->cwins;
  446.         for (lost = won = -1, n = 0;
  447.          (lost == -1 || won == -1) && n < number_cwins;
  448.          n++)
  449.         {
  450.         if (lost == -1 && cwins[n] == cwin)
  451.         {
  452.             lost = n;    /* This is the window which lost its colormap */
  453.             continue;
  454.         }
  455.  
  456.         if (won == -1 &&
  457.             cwins[n]->colormap->install_req == cevent->serial)
  458.         {
  459.             won = n;    /* This is the window whose colormap caused */
  460.             continue;    /* the de-install of the previous colormap */
  461.         }
  462.         }
  463.  
  464.         /*
  465.         ** Cases are:
  466.         ** Both the request and the window were found:
  467.         **        One of the installs made honoring the WM_COLORMAP
  468.         **        property caused another of the colormaps to be
  469.         **        de-installed, just mark the scoreboard.
  470.         **
  471.         ** Only the request was found:
  472.         **        One of the installs made honoring the WM_COLORMAP
  473.         **        property caused a window not in the WM_COLORMAP
  474.         **        list to lose its map.  This happens when the map
  475.         **        it is losing is one which is trying to be installed,
  476.         **        but is getting getting de-installed by another map
  477.         **        in this case, we'll get a scoreable event later,
  478.         **        this one is meaningless.
  479.         **
  480.         ** Neither the request nor the window was found:
  481.         **        Somebody called installcolormap, but it doesn't
  482.         **        affect the WM_COLORMAP windows.  This case will
  483.         **        probably never occur.
  484.         **
  485.         ** Only the window was found:
  486.         **        One of the WM_COLORMAP windows lost its colormap
  487.         **        but it wasn't one of the requests known.  This is
  488.         **        probably because someone did an "InstallColormap".
  489.         **        The colormap policy is "enforced" by re-installing
  490.         **        the colormaps which are believed to be correct.
  491.         */
  492.  
  493.         if (won != -1)
  494.         if (lost != -1)
  495.         {
  496.             /* lower diagonal index calculation */
  497.             if (lost > won)
  498.             n = lost*(lost-1)/2 + won;
  499.             else
  500.             n = won*(won-1)/2 + lost;
  501.             Scr->cmapInfo.cmaps->scoreboard[n] = 1;
  502.         } else
  503.         {
  504.             /*
  505.             ** One of the cwin installs caused one of the cwin
  506.             ** colormaps to be de-installed, so I'm sure to get an
  507.             ** UninstallNotify for the cwin I know about later.
  508.             ** I haven't got it yet, or the test of CM_INSTALLED
  509.             ** above would have failed.  Turning the CM_INSTALLED
  510.             ** bit back on makes sure we get back here to score
  511.             ** the collision.
  512.             */
  513.             cmap->state |= CM_INSTALLED;
  514.         }
  515.         else if (lost != -1)
  516.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  517.     }
  518.     }
  519.  
  520.     else if (cevent->state == ColormapUninstalled)
  521.     cmap->state &= ~CM_INSTALLED;
  522.  
  523.     else if (cevent->state == ColormapInstalled)
  524.     cmap->state |= CM_INSTALLED;
  525. }
  526.  
  527.  
  528.  
  529. /***********************************************************************
  530.  *
  531.  *  Procedure:
  532.  *    HandleVisibilityNotify - visibility notify event handler
  533.  *
  534.  * This routine keeps track of visibility events so that colormap
  535.  * installation can keep the maximum number of useful colormaps
  536.  * installed at one time.
  537.  *
  538.  ***********************************************************************
  539.  */
  540.  
  541. void
  542. HandleVisibilityNotify()
  543. {
  544.     XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
  545.     ColormapWindow *cwin;
  546.     TwmColormap *cmap;
  547.  
  548. #ifdef DEBUG_EVENTS
  549.     printf("HandleVisibilityNotify()\n");
  550. #endif
  551.     if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
  552.     return;
  553.     
  554.     /*
  555.      * when Saber complains about retreiving an <int> from an <unsigned int>
  556.      * just type "touch vevent->state" and "cont"
  557.      */
  558.     cmap = cwin->colormap;
  559.     if ((cmap->state & CM_INSTALLABLE) &&
  560.     vevent->state != cwin->visibility &&
  561.     (vevent->state == VisibilityFullyObscured ||
  562.      cwin->visibility == VisibilityFullyObscured) &&
  563.     cmap->w == cwin->w) {
  564.     cwin->visibility = vevent->state;
  565.     InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
  566.     } else
  567.     cwin->visibility = vevent->state;
  568. }
  569.  
  570.  
  571.  
  572. /***********************************************************************
  573.  *
  574.  *  Procedure:
  575.  *    HandleKeyPress - key press event handler
  576.  *
  577.  ***********************************************************************
  578.  */
  579.  
  580. void
  581. HandleKeyPress()
  582. {
  583.     FuncKey *key;
  584.     int len;
  585.     unsigned int modifier;
  586.  
  587. #ifdef DEBUG_EVENTS
  588.     printf("HandleKeyPress()\n");
  589. #endif
  590.     if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
  591.     Context = C_NO_CONTEXT;
  592.  
  593.     if (Event.xany.window == Scr->Root)
  594.     Context = C_ROOT;
  595.     if (Tmp_win)
  596.     {
  597.     if (Event.xany.window == Tmp_win->title_w)
  598.         Context = C_TITLE;
  599.     if (Event.xany.window == Tmp_win->w)
  600.         Context = C_WINDOW;
  601.     if (Event.xany.window == Tmp_win->icon_w)
  602.         Context = C_ICON;
  603.     if (Event.xany.window == Tmp_win->frame)
  604.         Context = C_FRAME;
  605.     if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
  606.         Context = C_ICONMGR;
  607.     if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
  608.         Context = C_ICONMGR;
  609.     }
  610.  
  611.     modifier = (Event.xkey.state & mods_used);
  612.     for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
  613.     {
  614.     if (key->keycode == Event.xkey.keycode &&
  615.         key->mods == modifier &&
  616.         (key->cont == Context || key->cont == C_NAME))
  617.     {
  618.         /* weed out the functions that don't make sense to execute
  619.          * from a key press 
  620.          */
  621.         if (key->func == F_MOVE || key->func == F_RESIZE)
  622.         return;
  623.  
  624.         if (key->cont != C_NAME)
  625.         {
  626.         ExecuteFunction(key->func, key->action, Event.xany.window,
  627.             Tmp_win, &Event, Context, FALSE);
  628.         XUngrabPointer(dpy, CurrentTime);
  629.         return;
  630.         }
  631.         else
  632.         {
  633.         int matched = FALSE;
  634.         len = strlen(key->win_name);
  635.  
  636.         /* try and match the name first */
  637.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  638.             Tmp_win = Tmp_win->next)
  639.         {
  640.             if (!strncmp(key->win_name, Tmp_win->name, len))
  641.             {
  642.             matched = TRUE;
  643.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  644.                 Tmp_win, &Event, C_FRAME, FALSE);
  645.             XUngrabPointer(dpy, CurrentTime);
  646.             }
  647.         }
  648.  
  649.         /* now try the res_name */
  650.         if (!matched)
  651.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  652.             Tmp_win = Tmp_win->next)
  653.         {
  654.             if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
  655.             {
  656.             matched = TRUE;
  657.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  658.                 Tmp_win, &Event, C_FRAME, FALSE);
  659.             XUngrabPointer(dpy, CurrentTime);
  660.             }
  661.         }
  662.  
  663.         /* now try the res_class */
  664.         if (!matched)
  665.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  666.             Tmp_win = Tmp_win->next)
  667.         {
  668.             if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
  669.             {
  670.             matched = TRUE;
  671.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  672.                 Tmp_win, &Event, C_FRAME, FALSE);
  673.             XUngrabPointer(dpy, CurrentTime);
  674.             }
  675.         }
  676.         if (matched)
  677.             return;
  678.         }
  679.     }
  680.     }
  681.  
  682.     /* if we get here, no function key was bound to the key.  Send it
  683.      * to the client if it was in a window we know about.
  684.      */
  685.     if (Tmp_win)
  686.     {
  687.         if (Event.xany.window == Tmp_win->icon_w ||
  688.         Event.xany.window == Tmp_win->frame ||
  689.         Event.xany.window == Tmp_win->title_w ||
  690.         (Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
  691.         {
  692.             Event.xkey.window = Tmp_win->w;
  693.             XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
  694.         }
  695.     }
  696.  
  697. }
  698.  
  699.  
  700.  
  701. static void free_window_names (tmp, nukefull, nukename, nukeicon)
  702.     TwmWindow *tmp;
  703.     Bool nukefull, nukename, nukeicon;
  704. {
  705. /*
  706.  * XXX - are we sure that nobody ever sets these to another constant (check
  707.  * twm windows)?
  708.  */
  709.     if (tmp->name == tmp->full_name) nukefull = False;
  710.     if (tmp->icon_name == tmp->name) nukename = False;
  711.  
  712. #define isokay(v) ((v) && (v) != NoName)
  713.     if (nukefull && isokay(tmp->full_name)) XFree (tmp->full_name);
  714.     if (nukename && isokay(tmp->name)) XFree (tmp->name);
  715.     if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name);
  716. #undef isokay
  717.     return;
  718. }
  719.  
  720.  
  721.  
  722. void free_cwins (tmp)
  723.     TwmWindow *tmp;
  724. {
  725.     int i;
  726.     TwmColormap *cmap;
  727.  
  728.     if (tmp->cmaps.number_cwins) {
  729.     for (i = 0; i < tmp->cmaps.number_cwins; i++) {
  730.          if (--tmp->cmaps.cwins[i]->refcnt == 0) {
  731.         cmap = tmp->cmaps.cwins[i]->colormap;
  732.         if (--cmap->refcnt == 0) {
  733.             XDeleteContext(dpy, cmap->c, ColormapContext);
  734.             free((char *) cmap);
  735.         }
  736.         XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
  737.         free((char *) tmp->cmaps.cwins[i]);
  738.         }
  739.     }
  740.     free((char *) tmp->cmaps.cwins);
  741.     if (tmp->cmaps.number_cwins > 1) {
  742.         free(tmp->cmaps.scoreboard);
  743.         tmp->cmaps.scoreboard = NULL;
  744.     }
  745.     tmp->cmaps.number_cwins = 0;
  746.     }
  747. }
  748.  
  749.  
  750.  
  751. /***********************************************************************
  752.  *
  753.  *  Procedure:
  754.  *    HandlePropertyNotify - property notify event handler
  755.  *
  756.  ***********************************************************************
  757.  */
  758.  
  759. void
  760. HandlePropertyNotify()
  761. {
  762.     char *prop = NULL;
  763.     Atom actual = None;
  764.     int actual_format;
  765.     unsigned long nitems, bytesafter;
  766.     unsigned long valuemask;        /* mask for create windows */
  767.     XSetWindowAttributes attributes;    /* attributes for create windows */
  768.     Pixmap pm;
  769.  
  770. #ifdef DEBUG_EVENTS
  771.     printf("HandlePropertyNotify()\n");
  772. #endif
  773.     /* watch for standard colormap changes */
  774.     if (Event.xproperty.window == Scr->Root) {
  775.     XStandardColormap *maps = NULL;
  776.     int nmaps;
  777.  
  778.     switch (Event.xproperty.state) {
  779.       case PropertyNewValue:
  780.         if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, 
  781.                   Event.xproperty.atom)) {
  782.         /* if got one, then replace any existing entry */
  783.         InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
  784.         }
  785.         return;
  786.  
  787.       case PropertyDelete:
  788.         RemoveRGBColormap (Event.xproperty.atom);
  789.         return;
  790.     }
  791.     }
  792.  
  793.     if (!Tmp_win) return;        /* unknown window */
  794.  
  795. #define MAX_NAME_LEN 200L        /* truncate to this many */
  796. #define MAX_ICON_NAME_LEN 200L        /* ditto */
  797.  
  798.     switch (Event.xproperty.atom) {
  799.       case XA_WM_NAME:
  800.     if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L, 
  801.                 MAX_NAME_LEN, False, XA_STRING, &actual,
  802.                 &actual_format, &nitems, &bytesafter,
  803.                 (unsigned char **) &prop) != Success ||
  804.         actual == None)
  805.       return;
  806.     if (!prop) prop = NoName;
  807.     free_window_names (Tmp_win, True, True, False);
  808.  
  809.     Tmp_win->full_name = prop;
  810.     Tmp_win->name = prop;
  811.  
  812.     Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font,
  813.                       Tmp_win->name,
  814.                       strlen (Tmp_win->name));
  815.  
  816.     SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
  817.              Tmp_win->frame_width, Tmp_win->frame_height, -1);
  818.  
  819.     if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
  820.  
  821.     /*
  822.      * if the icon name is NoName, set the name of the icon to be
  823.      * the same as the window 
  824.      */
  825.     if (Tmp_win->icon_name == NoName) {
  826.         Tmp_win->icon_name = Tmp_win->name;
  827.         RedoIconName();
  828.     }
  829.     break;
  830.  
  831.       case XA_WM_ICON_NAME:
  832.     if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0, 
  833.                 MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
  834.                 &actual_format, &nitems, &bytesafter,
  835.                 (unsigned char **) &prop) != Success ||
  836.         actual == None)
  837.       return;
  838.     if (!prop) prop = NoName;
  839.     free_window_names (Tmp_win, False, False, True);
  840.     Tmp_win->icon_name = prop;
  841.  
  842.     RedoIconName();
  843.     break;
  844.  
  845.       case XA_WM_HINTS:
  846.     if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
  847.     Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
  848.  
  849.     if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
  850.       Tmp_win->group = Tmp_win->wmhints->window_group;
  851.  
  852.     if (!Tmp_win->forced && Tmp_win->wmhints &&
  853.         Tmp_win->wmhints->flags & IconWindowHint) {
  854.         if (Tmp_win->icon_w) {
  855.             int icon_x, icon_y;
  856.  
  857.         /*
  858.          * There's already an icon window.
  859.          * Try to find out where it is; if we succeed, move the new
  860.          * window to where the old one is.
  861.          */
  862.         if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
  863.           &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
  864.             /*
  865.              * Move the new icon window to where the old one was.
  866.              */
  867.             XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
  868.               icon_y);
  869.         }
  870.  
  871.         /*
  872.          * If the window is iconic, map the new icon window.
  873.          */
  874.         if (Tmp_win->icon)
  875.             XMapWindow(dpy, Tmp_win->wmhints->icon_window);
  876.  
  877.         /*
  878.          * Now, if the old window isn't ours, unmap it, otherwise
  879.          * just get rid of it completely.
  880.          */
  881.         if (Tmp_win->icon_not_ours) {
  882.             if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
  883.             XUnmapWindow(dpy, Tmp_win->icon_w);
  884.         } else
  885.             XDestroyWindow(dpy, Tmp_win->icon_w);
  886.  
  887.         /*
  888.          * The new icon window isn't our window, so note that fact
  889.          * so that we don't treat it as ours.
  890.          */
  891.         Tmp_win->icon_not_ours = TRUE;
  892.  
  893.         /*
  894.          * Now make the new window the icon window for this window,
  895.          * and set it up to work as such (select for key presses
  896.          * and button presses/releases, set up the contexts for it,
  897.          * and define the cursor for it).
  898.          */
  899.         Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
  900.         XSelectInput (dpy, Tmp_win->icon_w,
  901.           KeyPressMask | ButtonPressMask | ButtonReleaseMask);
  902.         XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
  903.         XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
  904.         XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
  905.         }
  906.     }
  907.  
  908.     if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
  909.         (Tmp_win->wmhints->flags & IconPixmapHint)) {
  910.         if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
  911.                    &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width, 
  912.                    (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
  913.         return;
  914.         }
  915.  
  916.         pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
  917.                 Tmp_win->icon_height, Scr->d_depth);
  918.  
  919.         FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
  920.         XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
  921.         Scr->NormalGC,
  922.         0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
  923.  
  924.         valuemask = CWBackPixmap;
  925.         attributes.background_pixmap = pm;
  926.  
  927.         if (Tmp_win->icon_bm_w)
  928.         XDestroyWindow(dpy, Tmp_win->icon_bm_w);
  929.  
  930.         Tmp_win->icon_bm_w =
  931.           XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
  932.                  (unsigned int) Tmp_win->icon_width,
  933.                  (unsigned int) Tmp_win->icon_height,
  934.                  (unsigned int) 0, Scr->d_depth,
  935.                  (unsigned int) CopyFromParent, Scr->d_visual,
  936.                  valuemask, &attributes);
  937.  
  938.         XFreePixmap (dpy, pm);
  939.         RedoIconName();
  940.     }
  941.     break;
  942.  
  943.       case XA_WM_NORMAL_HINTS:
  944.     GetWindowSizeHints (Tmp_win);
  945.     break;
  946.  
  947.       default:
  948.     if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
  949.         FetchWmColormapWindows (Tmp_win);    /* frees old data */
  950.         break;
  951.     } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
  952.         FetchWmProtocols (Tmp_win);
  953.         break;
  954.     }
  955.     break;
  956.     }
  957. }
  958.  
  959.  
  960.  
  961. /***********************************************************************
  962.  *
  963.  *  Procedure:
  964.  *    RedoIconName - procedure to re-position the icon window and name
  965.  *
  966.  ***********************************************************************
  967.  */
  968.  
  969. RedoIconName()
  970. {
  971.     int x, y;
  972.  
  973. #ifdef DEBUG_EVENTS
  974.     printf("RedoIconName()\n");
  975. #endif
  976.     if (Tmp_win->list)
  977.     {
  978.     /* let the expose event cause the repaint */
  979.     XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
  980.  
  981.     if (Scr->SortIconMgr)
  982.         SortIconManager(Tmp_win->list->iconmgr);
  983.     }
  984.  
  985.     if (Tmp_win->icon_w == NULL)
  986.     return;
  987.  
  988.     if (Tmp_win->icon_not_ours)
  989.     return;
  990.  
  991.     Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
  992.     Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  993.  
  994.     Tmp_win->icon_w_width += 6;
  995.     if (Tmp_win->icon_w_width < Tmp_win->icon_width)
  996.     {
  997.     Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
  998.     Tmp_win->icon_x += 3;
  999.     Tmp_win->icon_w_width = Tmp_win->icon_width;
  1000.     }
  1001.     else
  1002.     {
  1003.     Tmp_win->icon_x = 3;
  1004.     }
  1005.  
  1006.     if (Tmp_win->icon_w_width == Tmp_win->icon_width)
  1007.     x = 0;
  1008.     else
  1009.     x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
  1010.  
  1011.     y = 0;
  1012.  
  1013.     Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
  1014.     Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
  1015.  
  1016.     XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
  1017.     Tmp_win->icon_w_height);
  1018.     if (Tmp_win->icon_bm_w)
  1019.     {
  1020.     XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
  1021.     XMapWindow(dpy, Tmp_win->icon_bm_w);
  1022.     }
  1023.     if (Tmp_win->icon)
  1024.     {
  1025.     XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
  1026.     }
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /***********************************************************************
  1032.  *
  1033.  *  Procedure:
  1034.  *    HandleClientMessage - client message event handler
  1035.  *
  1036.  ***********************************************************************
  1037.  */
  1038.  
  1039. void
  1040. HandleClientMessage()
  1041. {
  1042. #ifdef DEBUG_EVENTS
  1043.     printf("HandleClientMessage()\n");
  1044. #endif
  1045.     if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
  1046.     {
  1047.     if (Tmp_win != NULL)
  1048.     {
  1049.         if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
  1050.         {
  1051.         XEvent button;
  1052.  
  1053.         XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
  1054.                   &(button.xmotion.x_root),
  1055.                   &(button.xmotion.y_root),
  1056.                   &JunkX, &JunkY, &JunkMask);
  1057.  
  1058.         ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
  1059.             Tmp_win, &button, FRAME, FALSE);
  1060.         XUngrabPointer(dpy, CurrentTime);
  1061.         }
  1062.     }
  1063.     }
  1064. }
  1065.  
  1066.  
  1067.  
  1068. /***********************************************************************
  1069.  *
  1070.  *  Procedure:
  1071.  *    HandleExpose - expose event handler
  1072.  *
  1073.  ***********************************************************************
  1074.  */
  1075.  
  1076. static void flush_expose();
  1077.  
  1078. void
  1079. HandleExpose()
  1080. {
  1081.     MenuRoot *tmp;
  1082. #ifdef DEBUG_EVENTS
  1083.     printf("HandleExpose()\n");
  1084. #endif
  1085.     if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
  1086.     {
  1087.     PaintMenu(tmp, &Event);
  1088.     return;
  1089.     }
  1090.  
  1091.     if (Event.xexpose.count != 0)
  1092.     return;
  1093.  
  1094.     if (Event.xany.window == Scr->InfoWindow && InfoLines)
  1095.     {
  1096.     int i;
  1097.     int height;
  1098.  
  1099.     FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
  1100.         Scr->DefaultFont.font->fid);
  1101.  
  1102.     height = Scr->DefaultFont.height+2;
  1103.     for (i = 0; i < InfoLines; i++)
  1104.     {
  1105.         XDrawString(dpy, Scr->InfoWindow, Scr->NormalGC,
  1106.         5, (i*height) + Scr->DefaultFont.y, Info[i], strlen(Info[i]));
  1107.     }
  1108.     flush_expose (Event.xany.window);
  1109.     } 
  1110.     else if (Tmp_win != NULL)
  1111.     {
  1112.     if (Event.xany.window == Tmp_win->title_w)
  1113.     {
  1114.         FBF(Tmp_win->title.fore, Tmp_win->title.back,
  1115.         Scr->TitleBarFont.font->fid);
  1116.  
  1117.         XDrawString (dpy, Tmp_win->title_w, Scr->NormalGC,
  1118.              Scr->TBInfo.titlex, Scr->TitleBarFont.y, 
  1119.              Tmp_win->name, strlen(Tmp_win->name));
  1120.         flush_expose (Event.xany.window);
  1121.     }
  1122.     else if (Event.xany.window == Tmp_win->icon_w)
  1123.     {
  1124.         FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back,
  1125.         Scr->IconFont.font->fid);
  1126.  
  1127.         XDrawString (dpy, Tmp_win->icon_w,
  1128.         Scr->NormalGC,
  1129.         Tmp_win->icon_x, Tmp_win->icon_y,
  1130.         Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  1131.         flush_expose (Event.xany.window);
  1132.         return;
  1133.     } else if (Tmp_win->titlebuttons) {
  1134.         int i;
  1135.         Window w = Event.xany.window;
  1136.         register TBWindow *tbw;
  1137.         int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1138.  
  1139.         for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
  1140.         if (w == tbw->window) {
  1141.             register TitleButton *tb = tbw->info;
  1142.  
  1143.             FB(Tmp_win->title.fore, Tmp_win->title.back);
  1144.             XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
  1145.                 tb->srcx, tb->srcy, tb->width, tb->height,
  1146.                 tb->dstx, tb->dsty, 1);
  1147.             flush_expose (w);
  1148.             return;
  1149.         }
  1150.         }
  1151.     }
  1152.     if (Tmp_win->list) {
  1153.         if (Event.xany.window == Tmp_win->list->w)
  1154.         {
  1155.         FBF(Tmp_win->list->fore, Tmp_win->list->back,
  1156.             Scr->IconManagerFont.font->fid);
  1157.         XDrawString (dpy, Event.xany.window, Scr->NormalGC, 
  1158.             iconmgr_textx, Scr->IconManagerFont.y+4,
  1159.             Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  1160.         DrawIconManagerBorder(Tmp_win->list);
  1161.         flush_expose (Event.xany.window);
  1162.         return;
  1163.         }
  1164.         if (Event.xany.window == Tmp_win->list->icon)
  1165.         {
  1166.         FB(Tmp_win->list->fore, Tmp_win->list->back);
  1167.         XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
  1168.             Scr->NormalGC,
  1169.             0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
  1170.         flush_expose (Event.xany.window);
  1171.         return;
  1172.         }
  1173.     } 
  1174.     }
  1175. }
  1176.  
  1177.  
  1178.  
  1179. static void remove_window_from_ring (tmp)
  1180.     TwmWindow *tmp;
  1181. {
  1182.     TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;
  1183.  
  1184.     if (enter_win == tmp) {
  1185.     enter_flag = FALSE;
  1186.     enter_win = NULL;
  1187.     }
  1188.     if (raise_win == Tmp_win) raise_win = NULL;
  1189.  
  1190.     /*
  1191.      * 1. Unlink window
  1192.      * 2. If window was only thing in ring, null out ring
  1193.      * 3. If window was ring leader, set to next (or null)
  1194.      */
  1195.     if (prev) prev->ring.next = next;
  1196.     if (next) next->ring.prev = prev;
  1197.     if (Scr->Ring == tmp) 
  1198.       Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);
  1199.  
  1200.     if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
  1201. }
  1202.  
  1203.  
  1204.  
  1205. /***********************************************************************
  1206.  *
  1207.  *  Procedure:
  1208.  *    HandleDestroyNotify - DestroyNotify event handler
  1209.  *
  1210.  ***********************************************************************
  1211.  */
  1212.  
  1213. void
  1214. HandleDestroyNotify()
  1215. {
  1216.     int i;
  1217.  
  1218.     /*
  1219.      * Warning, this is also called by HandleUnmapNotify; if it ever needs to
  1220.      * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
  1221.      * into a DestroyNotify.
  1222.      */
  1223.  
  1224. #ifdef DEBUG_EVENTS
  1225.     printf("HandleDestroyNotify()\n");
  1226. #endif
  1227.     if (Tmp_win == NULL)
  1228.     return;
  1229.  
  1230.     if (Tmp_win == Scr->Focus)
  1231.     {
  1232.     FocusOnRoot();
  1233.     }
  1234.     XDeleteContext(dpy, Tmp_win->w, TwmContext);
  1235.     XDeleteContext(dpy, Tmp_win->w, ScreenContext);
  1236.     XDeleteContext(dpy, Tmp_win->frame, TwmContext);
  1237.     XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
  1238.     if (Tmp_win->icon_w)
  1239.     {
  1240.     XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
  1241.     XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
  1242.     }
  1243.     if (Tmp_win->title_height)
  1244.     {
  1245.     int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1246.     XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
  1247.     XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
  1248.     if (Tmp_win->hilite_w)
  1249.     {
  1250.         XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
  1251.         XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
  1252.     }
  1253.     if (Tmp_win->titlebuttons) {
  1254.         for (i = 0; i < nb; i++) {
  1255.         XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
  1256.                 TwmContext);
  1257.         XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
  1258.                 ScreenContext);
  1259.         }
  1260.         }
  1261.     }
  1262.  
  1263.     if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
  1264.     InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
  1265.  
  1266.     /*
  1267.      * TwmWindows contain the following pointers
  1268.      * 
  1269.      *     1.  full_name
  1270.      *     2.  name
  1271.      *     3.  icon_name
  1272.      *     4.  wmhints
  1273.      *     5.  class.res_name
  1274.      *     6.  class.res_class
  1275.      *     7.  list
  1276.      *     8.  iconmgrp
  1277.      *     9.  cwins
  1278.      *     10. titlebuttons
  1279.      *     11. window ring
  1280.      */
  1281.     if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
  1282.  
  1283.     XDestroyWindow(dpy, Tmp_win->frame);
  1284.     if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
  1285.     XDestroyWindow(dpy, Tmp_win->icon_w);
  1286.     IconDown (Tmp_win);
  1287.     }
  1288.     RemoveIconManager(Tmp_win);                    /* 7 */
  1289.     Tmp_win->prev->next = Tmp_win->next;
  1290.     if (Tmp_win->next != NULL)
  1291.     Tmp_win->next->prev = Tmp_win->prev;
  1292.     if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
  1293.  
  1294.     free_window_names (Tmp_win, True, True, True);        /* 1, 2, 3 */
  1295.     if (Tmp_win->wmhints)                    /* 4 */
  1296.       XFree ((char *)Tmp_win->wmhints);
  1297.     if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName)  /* 5 */
  1298.       XFree ((char *)Tmp_win->class.res_name);
  1299.     if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
  1300.       XFree ((char *)Tmp_win->class.res_class);
  1301.     free_cwins (Tmp_win);                /* 9 */
  1302.     if (Tmp_win->titlebuttons)                    /* 10 */
  1303.       free ((char *) Tmp_win->titlebuttons);
  1304.     remove_window_from_ring (Tmp_win);                /* 11 */
  1305.  
  1306.     free((char *)Tmp_win);
  1307. }
  1308.  
  1309.  
  1310.  
  1311. void
  1312. HandleCreateNotify()
  1313. {
  1314. #ifdef DEBUG_EVENTS
  1315.     fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
  1316.     fflush(stderr);
  1317.     XBell(dpy, 0);
  1318.     XSync(dpy, 0);
  1319. #endif
  1320. }
  1321.  
  1322.  
  1323.  
  1324. /***********************************************************************
  1325.  *
  1326.  *  Procedure:
  1327.  *    HandleMapRequest - MapRequest event handler
  1328.  *
  1329.  ***********************************************************************
  1330.  */
  1331.  
  1332. void
  1333. HandleMapRequest()
  1334. {
  1335.     int stat;
  1336.     int zoom_save;
  1337.  
  1338. #ifdef DEBUG_EVENTS
  1339.     printf("HandleMapRequest()\n");
  1340. #endif
  1341.     Event.xany.window = Event.xmaprequest.window;
  1342.     stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
  1343.     if (stat == XCNOENT)
  1344.     Tmp_win = NULL;
  1345.  
  1346.     /* If the window has never been mapped before ... */
  1347.     if (Tmp_win == NULL)
  1348.     {
  1349.     /* Add decorations. */
  1350.     Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
  1351.     if (Tmp_win == NULL)
  1352.         return;
  1353.     }
  1354.     else
  1355.     {
  1356.     /*
  1357.      * If the window has been unmapped by the client, it won't be listed
  1358.      * in the icon manager.  Add it again, if requested.
  1359.      */
  1360.     if (Tmp_win->list == NULL)
  1361.         (void) AddIconManager (Tmp_win);
  1362.     }
  1363.  
  1364.     /* If it's not merely iconified, and we have hints, use them. */
  1365.     if ((! Tmp_win->icon) &&
  1366.     Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
  1367.     {
  1368.     int state;
  1369.     Window icon;
  1370.  
  1371.     /* use WM_STATE if enabled */
  1372.     if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
  1373.           (state == NormalState || state == IconicState)))
  1374.       state = Tmp_win->wmhints->initial_state;
  1375.  
  1376.     switch (state) 
  1377.     {
  1378.         case DontCareState:
  1379.         case NormalState:
  1380.         case ZoomState:
  1381.         case InactiveState:
  1382.         XMapWindow(dpy, Tmp_win->w);
  1383.         XMapWindow(dpy, Tmp_win->frame);
  1384.         SetMapStateProp(Tmp_win, NormalState);
  1385.         SetRaiseWindow (Tmp_win);
  1386.         break;
  1387.  
  1388.         case IconicState:
  1389.         zoom_save = Scr->DoZoom;
  1390.         Scr->DoZoom = FALSE;
  1391.         Iconify(Tmp_win, 0, 0);
  1392.         Scr->DoZoom = zoom_save;
  1393.         break;
  1394.     }
  1395.     }
  1396.     /* If no hints, or currently an icon, just "deiconify" */
  1397.     else
  1398.     {
  1399.     DeIconify(Tmp_win);
  1400.     SetRaiseWindow (Tmp_win);
  1401.     }
  1402. }
  1403.  
  1404.  
  1405.  
  1406. void SimulateMapRequest (w)
  1407.     Window w;
  1408. {
  1409.     Event.xmaprequest.window = w;
  1410.     HandleMapRequest ();
  1411. }
  1412.  
  1413.  
  1414.  
  1415. /***********************************************************************
  1416.  *
  1417.  *  Procedure:
  1418.  *    HandleMapNotify - MapNotify event handler
  1419.  *
  1420.  ***********************************************************************
  1421.  */
  1422.  
  1423. void
  1424. HandleMapNotify()
  1425. {
  1426. #ifdef DEBUG_EVENTS
  1427.     printf("HandleMapNotify()\n");
  1428. #endif
  1429.     if (Tmp_win == NULL)
  1430.     return;
  1431.  
  1432.     /*
  1433.      * Need to do the grab to avoid race condition of having server send
  1434.      * MapNotify to client before the frame gets mapped; this is bad because
  1435.      * the client would think that the window has a chance of being viewable
  1436.      * when it really isn't.
  1437.      */
  1438.     XGrabServer (dpy);
  1439.     if (Tmp_win->icon_w)
  1440.     XUnmapWindow(dpy, Tmp_win->icon_w);
  1441.     if (Tmp_win->title_w)
  1442.     XMapSubwindows(dpy, Tmp_win->title_w);
  1443.     XMapSubwindows(dpy, Tmp_win->frame);
  1444.     if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
  1445.     XUnmapWindow(dpy, Tmp_win->hilite_w);
  1446.  
  1447.     XMapWindow(dpy, Tmp_win->frame);
  1448.     XUngrabServer (dpy);
  1449.     XFlush (dpy);
  1450.     Tmp_win->mapped = TRUE;
  1451.     Tmp_win->icon = FALSE;
  1452.     Tmp_win->icon_on = FALSE;
  1453. }
  1454.  
  1455.  
  1456.  
  1457. /***********************************************************************
  1458.  *
  1459.  *  Procedure:
  1460.  *    HandleUnmapNotify - UnmapNotify event handler
  1461.  *
  1462.  ***********************************************************************
  1463.  */
  1464.  
  1465. void
  1466. HandleUnmapNotify()
  1467. {
  1468.     int dstx, dsty;
  1469.     Window dumwin;
  1470.  
  1471. #ifdef DEBUG_EVENTS
  1472.     printf("HandleUnmapNotify()\n");
  1473. #endif
  1474.     /*
  1475.      * The July 27, 1988 ICCCM spec states that a client wishing to switch
  1476.      * to WithdrawnState should send a synthetic UnmapNotify with the
  1477.      * event field set to (pseudo-)root, in case the window is already
  1478.      * unmapped (which is the case for twm for IconicState).  Unfortunately,
  1479.      * we looked for the TwmContext using that field, so try the window
  1480.      * field also.
  1481.      */
  1482.     if (Tmp_win == NULL)
  1483.     {
  1484.     Event.xany.window = Event.xunmap.window;
  1485.     if (XFindContext(dpy, Event.xany.window,
  1486.         TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
  1487.         Tmp_win = NULL;
  1488.     }
  1489.  
  1490.     if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
  1491.     return;
  1492.  
  1493.     /*
  1494.      * The program may have unmapped the client window, from either
  1495.      * NormalState or IconicState.  Handle the transition to WithdrawnState.
  1496.      *
  1497.      * We need to reparent the window back to the root (so that twm exiting 
  1498.      * won't cause it to get mapped) and then throw away all state (pretend 
  1499.      * that we've received a DestroyNotify).
  1500.      */
  1501.  
  1502.     XGrabServer (dpy);
  1503.     if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
  1504.                    0, 0, &dstx, &dsty, &dumwin)) {
  1505.     XEvent ev;
  1506.     Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window, 
  1507.                           ReparentNotify, &ev);
  1508.     SetMapStateProp (Tmp_win, WithdrawnState);
  1509.     if (reparented) {
  1510.         if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
  1511.                             Event.xunmap.window, 
  1512.                             Tmp_win->old_bw);
  1513.         if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
  1514.           XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
  1515.     } else {
  1516.         XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
  1517.                  dstx, dsty);
  1518.         RestoreWithdrawnLocation (Tmp_win);
  1519.     }
  1520.     XRemoveFromSaveSet (dpy, Event.xunmap.window);
  1521.     XSelectInput (dpy, Event.xunmap.window, NoEventMask);
  1522.     HandleDestroyNotify ();        /* do not need to mash event before */
  1523.     } /* else window no longer exists and we'll get a destroy notify */
  1524.     XUngrabServer (dpy);
  1525.     XFlush (dpy);
  1526. }
  1527.  
  1528.  
  1529.  
  1530. /***********************************************************************
  1531.  *
  1532.  *  Procedure:
  1533.  *    HandleMotionNotify - MotionNotify event handler
  1534.  *
  1535.  ***********************************************************************
  1536.  */
  1537.  
  1538. void
  1539. HandleMotionNotify()
  1540. {
  1541. #ifdef DEBUG_EVENTS
  1542.     printf("HandleMotionNotify()\n");
  1543. #endif
  1544.     if (ResizeWindow != NULL)
  1545.     {
  1546.     XQueryPointer( dpy, Event.xany.window,
  1547.         &(Event.xmotion.root), &JunkChild,
  1548.         &(Event.xmotion.x_root), &(Event.xmotion.y_root),
  1549.         &(Event.xmotion.x), &(Event.xmotion.y),
  1550.         &JunkMask);
  1551.  
  1552.     /* Set WindowMoved appropriately so that f.deltastop will
  1553.        work with resize as well as move. */
  1554.     if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
  1555.         || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
  1556.       WindowMoved = TRUE;
  1557.  
  1558.     XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
  1559.     DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
  1560.     }
  1561. }
  1562.  
  1563.  
  1564.  
  1565. /***********************************************************************
  1566.  *
  1567.  *  Procedure:
  1568.  *    HandleButtonRelease - ButtonRelease event handler
  1569.  *
  1570.  ***********************************************************************
  1571.  */
  1572. void
  1573. HandleButtonRelease()
  1574. {
  1575.     int xl, xr, yt, yb, w, h;
  1576.     unsigned mask;
  1577.  
  1578. #ifdef DEBUG_EVENTS
  1579.     printf("HandleButtonRelease()\n");
  1580. #endif
  1581.     if (InfoLines)         /* delete info box on 2nd button release  */
  1582.       if (Context == C_IDENTIFY) {
  1583.     XUnmapWindow(dpy, Scr->InfoWindow);
  1584.     InfoLines = 0;
  1585.     Context = C_NO_CONTEXT;
  1586.       }
  1587.  
  1588.     if (DragWindow != None)
  1589.     {
  1590.     MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  1591.  
  1592.     XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
  1593.     if (DragWindow == Tmp_win->frame)
  1594.     {
  1595.         xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
  1596.         yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
  1597.         w = DragWidth + 2 * Tmp_win->frame_bw;
  1598.         h = DragHeight + 2 * Tmp_win->frame_bw;
  1599.     }
  1600.     else
  1601.     {
  1602.         xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
  1603.         yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
  1604.         w = DragWidth + 2 * Scr->IconBorderWidth;
  1605.         h = DragHeight + 2 * Scr->IconBorderWidth;
  1606.     }
  1607.  
  1608.     if (ConstMove)
  1609.     {
  1610.         if (ConstMoveDir == MOVE_HORIZ)
  1611.         yt = ConstMoveY;
  1612.  
  1613.         if (ConstMoveDir == MOVE_VERT)
  1614.         xl = ConstMoveX;
  1615.  
  1616.         if (ConstMoveDir == MOVE_NONE)
  1617.         {
  1618.         yt = ConstMoveY;
  1619.         xl = ConstMoveX;
  1620.         }
  1621.     }
  1622.     
  1623.     if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
  1624.     {
  1625.         xr = xl + w;
  1626.         yb = yt + h;
  1627.  
  1628.         if (xl < 0)
  1629.         xl = 0;
  1630.         if (xr > Scr->MyDisplayWidth)
  1631.         xl = Scr->MyDisplayWidth - w;
  1632.  
  1633.         if (yt < 0)
  1634.         yt = 0;
  1635.         if (yb > Scr->MyDisplayHeight)
  1636.         yt = Scr->MyDisplayHeight - h;
  1637.     }
  1638.  
  1639.     CurrentDragX = xl;
  1640.     CurrentDragY = yt;
  1641.     if (DragWindow == Tmp_win->frame)
  1642.       SetupWindow (Tmp_win, xl, yt,
  1643.                Tmp_win->frame_width, Tmp_win->frame_height, -1);
  1644.     else
  1645.         XMoveWindow (dpy, DragWindow, xl, yt);
  1646.  
  1647.     if (!Scr->NoRaiseMove && !Scr->OpaqueMove)    /* opaque already did */
  1648.         XRaiseWindow(dpy, DragWindow);
  1649.  
  1650.     if (!Scr->OpaqueMove)
  1651.         UninstallRootColormap();
  1652.     else
  1653.         XSync(dpy, 0);
  1654.  
  1655.     if (Scr->NumAutoRaises) {
  1656.         enter_flag = TRUE;
  1657.         enter_win = NULL;
  1658.         raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
  1659.              ? Tmp_win : NULL);
  1660.     }
  1661.  
  1662.     DragWindow = NULL;
  1663.     ConstMove = FALSE;
  1664.     }
  1665.  
  1666.     if (ResizeWindow != NULL)
  1667.     {
  1668.     EndResize();
  1669.     }
  1670.  
  1671.     if (ActiveMenu != NULL && RootFunction == NULL)
  1672.     {
  1673.     if (ActiveItem != NULL)
  1674.     {
  1675.         int func = ActiveItem->func;
  1676.         Action = ActiveItem->action;
  1677.         switch (func) {
  1678.           case F_MOVE:
  1679.           case F_FORCEMOVE:
  1680.         ButtonPressed = -1;
  1681.         break;
  1682.           case F_CIRCLEUP:
  1683.           case F_CIRCLEDOWN:
  1684.           case F_REFRESH:
  1685.           case F_WARPTOSCREEN:
  1686.         PopDownMenu();
  1687.         break;
  1688.           default:
  1689.         break;
  1690.         }
  1691.         ExecuteFunction(func, Action,
  1692.         ButtonWindow ? ButtonWindow->frame : None,
  1693.         ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
  1694.         Context = C_NO_CONTEXT;
  1695.         ButtonWindow = NULL;
  1696.  
  1697.         /* if we are not executing a defered command, then take down the
  1698.          * menu
  1699.          */
  1700.         if (RootFunction == NULL)
  1701.         {
  1702.         PopDownMenu();
  1703.         }
  1704.     }
  1705.     else
  1706.         PopDownMenu();
  1707.     }
  1708.  
  1709.     mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
  1710.     switch (Event.xbutton.button)
  1711.     {
  1712.     case Button1: mask &= ~Button1Mask; break;
  1713.     case Button2: mask &= ~Button2Mask; break;
  1714.     case Button3: mask &= ~Button3Mask; break;
  1715.     case Button4: mask &= ~Button4Mask; break;
  1716.     case Button5: mask &= ~Button5Mask; break;
  1717.     }
  1718.  
  1719.     if (RootFunction != NULL ||
  1720.     ResizeWindow != None ||
  1721.     DragWindow != None)
  1722.     ButtonPressed = -1;
  1723.  
  1724.     if (RootFunction == NULL &&
  1725.     (Event.xbutton.state & mask) == 0 &&
  1726.     DragWindow == None &&
  1727.     ResizeWindow == None)
  1728.     {
  1729.     XUngrabPointer(dpy, CurrentTime);
  1730.     XUngrabServer(dpy);
  1731.     XFlush(dpy);
  1732.     EventHandler[EnterNotify] = HandleEnterNotify;
  1733.     EventHandler[LeaveNotify] = HandleLeaveNotify;
  1734.     ButtonPressed = -1;
  1735.     if (DownIconManager)
  1736.     {
  1737.         DownIconManager->down = FALSE;
  1738.         if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
  1739.         DownIconManager = NULL;
  1740.     }
  1741.     Cancel = FALSE;
  1742.     }
  1743. }
  1744.  
  1745.  
  1746.  
  1747. static do_menu (menu, w)
  1748.     MenuRoot *menu;            /* menu to pop up */
  1749.     Window w;                /* invoking window or None */
  1750. {
  1751.     int x = Event.xbutton.x_root;
  1752.     int y = Event.xbutton.y_root;
  1753.     Bool center;
  1754.  
  1755. #ifdef DEBUG_EVENTS
  1756.     printf("do_menu()\n");
  1757. #endif
  1758.     if (!Scr->NoGrabServer)
  1759.     XGrabServer(dpy);
  1760.     if (w) {
  1761.     int h = Scr->TBInfo.width - Scr->TBInfo.border;
  1762.     Window child;
  1763.  
  1764.     (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
  1765.     center = False;
  1766.     } else {
  1767.     center = True;
  1768.     }
  1769.     if (PopUpMenu (menu, x, y, center)) {
  1770.     UpdateMenu();
  1771.     } else {
  1772.     XBell (dpy, 0);
  1773.     }
  1774. }
  1775.  
  1776.  
  1777.  
  1778. /***********************************************************************
  1779.  *
  1780.  *  Procedure:
  1781.  *    HandleButtonPress - ButtonPress event handler
  1782.  *
  1783.  ***********************************************************************
  1784.  */
  1785. void
  1786. HandleButtonPress()
  1787. {
  1788.     unsigned int modifier;
  1789.     Cursor cur;
  1790.  
  1791. #ifdef DEBUG_EVENTS
  1792.     printf("HandleButtonPress()\n");
  1793. #endif
  1794.     /* pop down the menu, if any */
  1795.     if (ActiveMenu != NULL)
  1796.     PopDownMenu();
  1797.  
  1798.     XSync(dpy, 0);            /* XXX - remove? */
  1799.  
  1800.     if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */
  1801.     {
  1802.     /* we got another butt press in addition to one still held
  1803.      * down, we need to cancel the operation we were doing
  1804.      */
  1805.     Cancel = TRUE;
  1806.     CurrentDragX = origDragX;
  1807.     CurrentDragY = origDragY;
  1808.     if (!menuFromFrameOrWindowOrTitlebar)
  1809.       if (Scr->OpaqueMove && DragWindow != None) {
  1810.         XMoveWindow (dpy, DragWindow, origDragX, origDragY);
  1811.       } else {
  1812.         MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  1813.       }
  1814.     XUnmapWindow(dpy, Scr->SizeWindow);
  1815.     if (!Scr->OpaqueMove)
  1816.         UninstallRootColormap();
  1817.     ResizeWindow = None;
  1818.     DragWindow = None;
  1819.     cur = LeftButt;
  1820.     if (Event.xbutton.button == Button2)
  1821.         cur = MiddleButt;
  1822.     else if (Event.xbutton.button >= Button3)
  1823.         cur = RightButt;
  1824.  
  1825.     XGrabPointer(dpy, Scr->Root, True,
  1826.         ButtonReleaseMask | ButtonPressMask,
  1827.         GrabModeAsync, GrabModeAsync,
  1828.         Scr->Root, cur, CurrentTime);
  1829.  
  1830.     return;
  1831.     }
  1832.     else
  1833.     ButtonPressed = Event.xbutton.button;
  1834.  
  1835.     if (ResizeWindow != None ||
  1836.     DragWindow != None  ||
  1837.     ActiveMenu != NULL)
  1838.     return;
  1839.  
  1840.     /* check the title bar buttons */
  1841.     if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
  1842.     {
  1843.     register int i;
  1844.     register TBWindow *tbw;
  1845.     int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1846.  
  1847.     for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
  1848.         if (Event.xany.window == tbw->window) {
  1849.         if (tbw->info->func == F_MENU) {
  1850.             Context = C_TITLE;
  1851.             ButtonEvent = Event;
  1852.             ButtonWindow = Tmp_win;
  1853.             do_menu (tbw->info->menuroot, tbw->window);
  1854.         } else {
  1855.             ExecuteFunction (tbw->info->func, tbw->info->action,
  1856.                      Event.xany.window, Tmp_win, &Event,
  1857.                      C_TITLE, FALSE);
  1858.         }
  1859.         return;
  1860.         }
  1861.     }
  1862.     }
  1863.  
  1864.     Context = C_NO_CONTEXT;
  1865.  
  1866.     if (Event.xany.window == Scr->InfoWindow)
  1867.       Context = C_IDENTIFY;
  1868.  
  1869.     if (Event.xany.window == Scr->Root)
  1870.     Context = C_ROOT;
  1871.     if (Tmp_win)
  1872.     {
  1873.     if (Tmp_win->list && RootFunction != NULL &&
  1874.         (Event.xany.window == Tmp_win->list->w ||
  1875.         Event.xany.window == Tmp_win->list->icon))
  1876.     {
  1877.         Tmp_win = Tmp_win->list->iconmgr->twm_win;
  1878.         XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
  1879.         Event.xbutton.x, Event.xbutton.y, 
  1880.         &JunkX, &JunkY, &JunkChild);
  1881.  
  1882.         Event.xbutton.x = JunkX;
  1883.         Event.xbutton.y = JunkY - Tmp_win->title_height;
  1884.         Event.xany.window = Tmp_win->w;
  1885.         Context = C_WINDOW;
  1886.     }
  1887.     else if (Event.xany.window == Tmp_win->title_w)
  1888.     {
  1889.         Context = C_TITLE;
  1890.     }
  1891.     else if (Event.xany.window == Tmp_win->w) 
  1892.     {
  1893.         printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
  1894.         Context = C_WINDOW;
  1895.     }
  1896.     else if (Event.xany.window == Tmp_win->icon_w)
  1897.     {
  1898.         Context = C_ICON;
  1899.     }
  1900.     else if (Event.xany.window == Tmp_win->frame) 
  1901.     {
  1902.         /* since we now place a button grab on the frame instead
  1903.              * of the window, (see GrabButtons() in add_window.c), we
  1904.              * need to figure out where the pointer exactly is before
  1905.              * assigning Context.  If the pointer is on the application
  1906.              * window we will change the event structure to look as if
  1907.              * it came from the application window.
  1908.          */
  1909.         if (Event.xbutton.subwindow == Tmp_win->w) {
  1910.           Event.xbutton.window = Tmp_win->w;
  1911.               Event.xbutton.y -= Tmp_win->title_height;
  1912. /*****
  1913.               Event.xbutton.x -= Tmp_win->frame_bw;
  1914. *****/
  1915.           Context = C_WINDOW;
  1916.         }
  1917.             else Context = C_FRAME;
  1918.     }
  1919.     else if (Tmp_win->list &&
  1920.         (Event.xany.window == Tmp_win->list->w ||
  1921.         Event.xany.window == Tmp_win->list->icon))
  1922.     {
  1923.         Tmp_win->list->down = TRUE;
  1924.         if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
  1925.         DownIconManager = Tmp_win->list;
  1926.         Context = C_ICONMGR;
  1927.     }
  1928.     }
  1929.  
  1930.     /* this section of code checks to see if we were in the middle of
  1931.      * a command executed from a menu
  1932.      */
  1933.     if (RootFunction != NULL)
  1934.     {
  1935.     if (Event.xany.window == Scr->Root)
  1936.     {
  1937.         /* if the window was the Root, we don't know for sure it
  1938.          * it was the root.  We must check to see if it happened to be
  1939.          * inside of a client that was getting button press events.
  1940.          */
  1941.         XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
  1942.         Event.xbutton.x, 
  1943.         Event.xbutton.y, 
  1944.         &JunkX, &JunkY, &Event.xany.window);
  1945.  
  1946.         if (Event.xany.window == 0 ||
  1947.         (XFindContext(dpy, Event.xany.window, TwmContext,
  1948.                   (caddr_t *)&Tmp_win) == XCNOENT))
  1949.         {
  1950.         RootFunction = NULL;
  1951.         XBell(dpy, 0);
  1952.         return;
  1953.         }
  1954.  
  1955.         XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
  1956.         Event.xbutton.x, 
  1957.         Event.xbutton.y, 
  1958.         &JunkX, &JunkY, &JunkChild);
  1959.  
  1960.         Event.xbutton.x = JunkX;
  1961.         Event.xbutton.y = JunkY;
  1962.         Context = C_WINDOW;
  1963.     }
  1964.  
  1965.     /* make sure we are not trying to move an identify window */
  1966.     if (Event.xany.window != Scr->InfoWindow)
  1967.       ExecuteFunction(RootFunction, Action, Event.xany.window,
  1968.               Tmp_win, &Event, Context, FALSE);
  1969.  
  1970.     RootFunction = NULL;
  1971.     return;
  1972.     }
  1973.  
  1974.     ButtonEvent = Event;
  1975.     ButtonWindow = Tmp_win;
  1976.  
  1977.     /* if we get to here, we have to execute a function or pop up a 
  1978.      * menu
  1979.      */
  1980.     modifier = (Event.xbutton.state & mods_used);
  1981.  
  1982.     if (Context == C_NO_CONTEXT)
  1983.     return;
  1984.  
  1985.     RootFunction = NULL;
  1986.     if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
  1987.     {
  1988.     do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
  1989.          (Window) None);
  1990.     }
  1991.     else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != NULL)
  1992.     {
  1993.     Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ?
  1994.         Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL;
  1995.     ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func,
  1996.         Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
  1997.     }
  1998.     else if (Scr->DefaultFunction.func != NULL)
  1999.     {
  2000.     if (Scr->DefaultFunction.func == F_MENU)
  2001.     {
  2002.         do_menu (Scr->DefaultFunction.menu, (Window) None);
  2003.     }
  2004.     else
  2005.     {
  2006.         Action = Scr->DefaultFunction.item ?
  2007.         Scr->DefaultFunction.item->action : NULL;
  2008.         ExecuteFunction(Scr->DefaultFunction.func, Action,
  2009.            Event.xany.window, Tmp_win, &Event, Context, FALSE);
  2010.     }
  2011.     }
  2012. }
  2013.  
  2014.  
  2015.  
  2016. /***********************************************************************
  2017.  *
  2018.  *  Procedure:
  2019.  *    HENQueueScanner - EnterNotify event q scanner
  2020.  *
  2021.  *    Looks at the queued events and determines if any matching
  2022.  *    LeaveNotify events or EnterEvents deriving from the
  2023.  *    termination of a grab are behind this event to allow
  2024.  *    skipping of unnecessary processing.
  2025.  *
  2026.  ***********************************************************************
  2027.  */
  2028.  
  2029. typedef struct HENScanArgs {
  2030.     Window w;        /* Window we are currently entering */
  2031.     Bool leaves;    /* Any LeaveNotifies found for this window */
  2032.     Bool inferior;    /* Was NotifyInferior the mode for LeaveNotify */
  2033.     Bool enters;    /* Any EnterNotify events with NotifyUngrab */
  2034. } HENScanArgs;
  2035.  
  2036. /* ARGSUSED*/
  2037. static Bool
  2038. HENQueueScanner(dpy, ev, args)
  2039.     Display *dpy;
  2040.     XEvent *ev;
  2041.     char *args;
  2042. {
  2043. #ifdef DEBUG_EVENTS
  2044.     printf("HENQueueScanner()\n");
  2045. #endif
  2046.     if (ev->type == LeaveNotify) {
  2047.     if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
  2048.         ev->xcrossing.mode == NotifyNormal) {
  2049.         ((HENScanArgs *) args)->leaves = True;
  2050.         /*
  2051.          * Only the last event found matters for the Inferior field.
  2052.          */
  2053.         ((HENScanArgs *) args)->inferior =
  2054.         (ev->xcrossing.detail == NotifyInferior);
  2055.     }
  2056.     } else if (ev->type == EnterNotify) {
  2057.     if (ev->xcrossing.mode == NotifyUngrab)
  2058.         ((HENScanArgs *) args)->enters = True;
  2059.     }
  2060.  
  2061.     return (False);
  2062. }
  2063.  
  2064.  
  2065.  
  2066. /***********************************************************************
  2067.  *
  2068.  *  Procedure:
  2069.  *    HandleEnterNotify - EnterNotify event handler
  2070.  *
  2071.  ***********************************************************************
  2072.  */
  2073.  
  2074. void
  2075. HandleEnterNotify()
  2076. {
  2077.     MenuRoot *mr;
  2078.     XEnterWindowEvent *ewp = &Event.xcrossing;
  2079.     HENScanArgs scanArgs;
  2080.     XEvent dummy;
  2081.     
  2082. #ifdef DEBUG_EVENTS
  2083.     printf("HandleEnterNotify()\n");
  2084. #endif
  2085.     /*
  2086.      * Save the id of the window entered.  This will be used to remove
  2087.      * border highlight on entering the next application window.
  2088.      */
  2089.     if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
  2090.       SetBorder (UnHighLight_win, False);    /* application window */
  2091.       if (UnHighLight_win->list) /* in the icon box */
  2092.     NotActiveIconManager(UnHighLight_win->list);
  2093.     }
  2094.     if (ewp->window == Scr->Root)
  2095.       UnHighLight_win = NULL;
  2096.     else if (Tmp_win)
  2097.       UnHighLight_win = Tmp_win;
  2098.  
  2099.     /*
  2100.      * if we aren't in the middle of menu processing
  2101.      */
  2102.     if (!ActiveMenu) {
  2103.     /*
  2104.      * We're not interested in pseudo Enter/Leave events generated
  2105.      * from grab initiations.
  2106.      */
  2107.     if (ewp->mode == NotifyGrab)
  2108.         return;
  2109.  
  2110.     /*
  2111.      * Scan for Leave and Enter Notify events to see if we can avoid some
  2112.      * unnecessary processing.
  2113.      */
  2114.     scanArgs.w = ewp->window;
  2115.     scanArgs.leaves = scanArgs.enters = False;
  2116.     (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
  2117.  
  2118.     /*
  2119.      * if entering root window, restore twm default colormap so that 
  2120.      * titlebars are legible
  2121.      */
  2122.     if (ewp->window == Scr->Root) {
  2123.         if (!scanArgs.leaves && !scanArgs.enters)
  2124.         InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
  2125.         return;
  2126.     }
  2127.  
  2128.     /*
  2129.      * if we have an event for a specific one of our windows
  2130.      */
  2131.     if (Tmp_win) {
  2132.         /*
  2133.          * If currently in PointerRoot mode (indicated by FocusRoot), then
  2134.          * focus on this window
  2135.          */
  2136.         if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
  2137.         if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
  2138.         if (Tmp_win->mapped) {
  2139.             /*
  2140.              * unhighlight old focus window
  2141.              */
  2142.             if (Scr->Focus &&
  2143.             Scr->Focus != Tmp_win && Tmp_win->hilite_w)
  2144.               XUnmapWindow(dpy, Scr->Focus->hilite_w);
  2145.  
  2146.             /*
  2147.              * If entering the frame or the icon manager, then do 
  2148.              * "window activation things":
  2149.              *
  2150.              *     1.  turn on highlight window (if any)
  2151.              *     2.  install frame colormap
  2152.              *     3.  set frame and highlight window (if any) border
  2153.              *     4.  focus on client window to forward typing
  2154.              *     4a. same as 4 but for icon mgr w/with NoTitlebar on.
  2155.              *     5.  send WM_TAKE_FOCUS if requested
  2156.              */
  2157.             if (ewp->window == Tmp_win->frame ||
  2158.             (Tmp_win->list && ewp->window == Tmp_win->list->w)) {
  2159.             if (Tmp_win->hilite_w)                /* 1 */
  2160.               XMapWindow (dpy, Tmp_win->hilite_w);
  2161.             if (!scanArgs.leaves && !scanArgs.enters)
  2162.                 InstallWindowColormaps (EnterNotify,    /* 2 */
  2163.                             &Scr->TwmRoot);
  2164.             SetBorder (Tmp_win, True);            /* 3 */
  2165.             if (Tmp_win->title_w && Scr->TitleFocus &&    /* 4 */
  2166.                 Tmp_win->wmhints && Tmp_win->wmhints->input)
  2167.               SetFocus (Tmp_win, ewp->time);
  2168.             if (Scr->NoTitlebar && Scr->TitleFocus &&    /*4a */
  2169.                 Tmp_win->wmhints && Tmp_win->wmhints->input)
  2170.               SetFocus (Tmp_win, ewp->time);
  2171.             if (Tmp_win->protocols & DoesWmTakeFocus)    /* 5 */
  2172.               SendTakeFocusMessage (Tmp_win, ewp->time);
  2173.             Scr->Focus = Tmp_win;
  2174.             } else if (ewp->window == Tmp_win->w) {
  2175.             /*
  2176.              * If we are entering the application window, install
  2177.              * its colormap(s).
  2178.              */
  2179.             if (!scanArgs.leaves || scanArgs.inferior)
  2180.                 InstallWindowColormaps(EnterNotify, Tmp_win);
  2181.             }
  2182.         }            /* end if Tmp_win->mapped */
  2183.         if (Tmp_win->wmhints != NULL &&
  2184.             ewp->window == Tmp_win->wmhints->icon_window &&
  2185.             (!scanArgs.leaves || scanArgs.inferior))
  2186.                 InstallWindowColormaps(EnterNotify, Tmp_win);
  2187.         }                /* end if FocusRoot */
  2188.         /*
  2189.          * If this window is to be autoraised, mark it so
  2190.          */
  2191.         if (Tmp_win->auto_raise) {
  2192.         enter_win = Tmp_win;
  2193.         if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
  2194.         } else if (enter_flag && raise_win == Tmp_win)
  2195.           enter_win = Tmp_win;
  2196.         /*
  2197.          * set ring leader
  2198.          */
  2199.         if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
  2200.           Scr->RingLeader = Tmp_win;
  2201.         XSync (dpy, 0);
  2202.         return;
  2203.     }                /* end if Tmp_win */
  2204.     }                    /* end if !ActiveMenu */
  2205.  
  2206.     /*
  2207.      * Find the menu that we are dealing with now; punt if unknown
  2208.      */
  2209.     if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
  2210.  
  2211.     mr->entered = TRUE;
  2212.     if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == NULL) {
  2213.     if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
  2214.     XUnmapWindow (dpy, ActiveMenu->w);
  2215.     ActiveMenu->mapped = UNMAPPED;
  2216.     UninstallRootColormap ();
  2217.     if (ActiveItem) {
  2218.         ActiveItem->state = 0;
  2219.         PaintEntry (ActiveMenu, ActiveItem,  False);
  2220.     }
  2221.     ActiveItem = NULL;
  2222.     ActiveMenu = mr;
  2223.     MenuDepth--;
  2224.     }
  2225.     return;
  2226. }
  2227.  
  2228.  
  2229.  
  2230. /***********************************************************************
  2231.  *
  2232.  *  Procedure:
  2233.  *    HLNQueueScanner - LeaveNotify event q scanner
  2234.  *
  2235.  *    Looks at the queued events and determines if any
  2236.  *    EnterNotify events are behind this event to allow
  2237.  *    skipping of unnecessary processing.
  2238.  *
  2239.  ***********************************************************************
  2240.  */
  2241.  
  2242. typedef struct HLNScanArgs {
  2243.     Window w;        /* The window getting the LeaveNotify */
  2244.     Bool enters;    /* Any EnterNotify event at all */
  2245.     Bool matches;    /* Any matching EnterNotify events */
  2246. } HLNScanArgs;
  2247.  
  2248. /* ARGSUSED*/
  2249. static Bool
  2250. HLNQueueScanner(dpy, ev, args)
  2251.     Display *dpy;
  2252.     XEvent *ev;
  2253.     char *args;
  2254. {
  2255. #ifdef DEBUG_EVENTS
  2256.     printf("HLNQueueScanner()\n");
  2257. #endif
  2258.     if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
  2259.     ((HLNScanArgs *) args)->enters = True;
  2260.     if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
  2261.         ((HLNScanArgs *) args)->matches = True;
  2262.     }
  2263.  
  2264.     return (False);
  2265. }
  2266.  
  2267.  
  2268.  
  2269. /***********************************************************************
  2270.  *
  2271.  *  Procedure:
  2272.  *    HandleLeaveNotify - LeaveNotify event handler
  2273.  *
  2274.  ***********************************************************************
  2275.  */
  2276.  
  2277. void
  2278. HandleLeaveNotify()
  2279. {
  2280.     HLNScanArgs scanArgs;
  2281.     XEvent dummy;
  2282.  
  2283. #ifdef DEBUG_EVENTS
  2284.     printf("HandleLeaveNotify()\n");
  2285. #endif
  2286.     if (Tmp_win != NULL)
  2287.     {
  2288.     Bool inicon;
  2289.  
  2290.     /*
  2291.      * We're not interested in pseudo Enter/Leave events generated
  2292.      * from grab initiations and terminations.
  2293.      */
  2294.     if (Event.xcrossing.mode != NotifyNormal)
  2295.         return;
  2296.  
  2297.     inicon = (Tmp_win->list &&
  2298.           Tmp_win->list->w == Event.xcrossing.window);
  2299.  
  2300.     if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
  2301.         (Event.xcrossing.detail != NotifyInferior &&
  2302.          Event.xcrossing.window != Tmp_win->w)) {
  2303.         if (!inicon) {
  2304.         if (Tmp_win->mapped) {
  2305.             Tmp_win->ring.cursor_valid = False;
  2306.         } else {
  2307.             Tmp_win->ring.cursor_valid = True;
  2308.             Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
  2309.                         Tmp_win->frame_x);
  2310.             Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
  2311.                         Tmp_win->frame_y);
  2312.         }
  2313.         }
  2314.         Scr->RingLeader = (TwmWindow *) NULL;
  2315.     }
  2316.     if (Scr->FocusRoot) {
  2317.  
  2318.         if (Event.xcrossing.detail != NotifyInferior) {
  2319.  
  2320.         /*
  2321.          * Scan for EnterNotify events to see if we can avoid some
  2322.          * unnecessary processing.
  2323.          */
  2324.         scanArgs.w = Event.xcrossing.window;
  2325.         scanArgs.enters = scanArgs.matches = False;
  2326.         (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
  2327.                      (char *) &scanArgs);
  2328.  
  2329.         if ((Event.xcrossing.window == Tmp_win->frame &&
  2330.             !scanArgs.matches) || inicon) {
  2331.             if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
  2332.             if (Tmp_win->hilite_w)
  2333.               XUnmapWindow (dpy, Tmp_win->hilite_w);
  2334.             SetBorder (Tmp_win, False);
  2335.             if (Scr->TitleFocus ||
  2336.             Tmp_win->protocols & DoesWmTakeFocus)
  2337.               SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
  2338.             Scr->Focus = NULL;
  2339.         } else if (Event.xcrossing.window == Tmp_win->w &&
  2340.                 !scanArgs.enters) {
  2341.             InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
  2342.         }
  2343.         }
  2344.     }
  2345.     XSync (dpy, 0);
  2346.     return;
  2347.     }
  2348. }
  2349.  
  2350.  
  2351.  
  2352. /***********************************************************************
  2353.  *
  2354.  *  Procedure:
  2355.  *    HandleConfigureRequest - ConfigureRequest event handler
  2356.  *
  2357.  ***********************************************************************
  2358.  */
  2359.  
  2360. void
  2361. HandleConfigureRequest()
  2362. {
  2363.     XWindowChanges xwc;
  2364.     unsigned long xwcm;
  2365.     int x, y, width, height, bw;
  2366.     int gravx, gravy;
  2367.     XConfigureRequestEvent *cre = &Event.xconfigurerequest;
  2368.  
  2369. #ifdef DEBUG_EVENTS
  2370.     fprintf(stderr, "ConfigureRequest\n");
  2371.     if (cre->value_mask & CWX)
  2372.     fprintf(stderr, "  x = %d\n", cre->x);
  2373.     if (cre->value_mask & CWY)
  2374.     fprintf(stderr, "  y = %d\n", cre->y);
  2375.     if (cre->value_mask & CWWidth)
  2376.     fprintf(stderr, "  width = %d\n", cre->width);
  2377.     if (cre->value_mask & CWHeight)
  2378.     fprintf(stderr, "  height = %d\n", cre->height);
  2379.     if (cre->value_mask & CWSibling)
  2380.     fprintf(stderr, "  above = 0x%x\n", cre->above);
  2381.     if (cre->value_mask & CWStackMode)
  2382.     fprintf(stderr, "  stack = %d\n", cre->detail);
  2383. #endif
  2384.  
  2385.     /*
  2386.      * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
  2387.      * be wrong
  2388.      */
  2389.     Event.xany.window = cre->window;    /* mash parent field */
  2390.     if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
  2391.     XCNOENT)
  2392.       Tmp_win = NULL;
  2393.  
  2394.  
  2395.     /*
  2396.      * According to the July 27, 1988 ICCCM draft, we should ignore size and
  2397.      * position fields in the WM_NORMAL_HINTS property when we map a window.
  2398.      * Instead, we'll read the current geometry.  Therefore, we should respond
  2399.      * to configuration requests for windows which have never been mapped.
  2400.      */
  2401.     if (!Tmp_win || Tmp_win->icon_w == cre->window) {
  2402.     xwcm = cre->value_mask & 
  2403.         (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
  2404.     xwc.x = cre->x;
  2405.     xwc.y = cre->y;
  2406.     xwc.width = cre->width;
  2407.     xwc.height = cre->height;
  2408.     xwc.border_width = cre->border_width;
  2409.     XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
  2410.     return;
  2411.     }
  2412.  
  2413.     if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
  2414.     TwmWindow *otherwin;
  2415.  
  2416.     xwc.sibling = (((cre->value_mask & CWSibling) &&
  2417.             (XFindContext (dpy, cre->above, TwmContext,
  2418.                        (caddr_t *) &otherwin) == XCSUCCESS))
  2419.                ? otherwin->frame : cre->above);
  2420.     xwc.stack_mode = cre->detail;
  2421.     XConfigureWindow (dpy, Tmp_win->frame, 
  2422.               cre->value_mask & (CWSibling | CWStackMode), &xwc);
  2423.     }
  2424.  
  2425.  
  2426.     /* Don't modify frame_XXX fields before calling SetupWindow! */
  2427.     x = Tmp_win->frame_x;
  2428.     y = Tmp_win->frame_y;
  2429.     width = Tmp_win->frame_width;
  2430.     height = Tmp_win->frame_height;
  2431.     bw = Tmp_win->frame_bw;
  2432.  
  2433.     /*
  2434.      * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
  2435.      * configure request are for the upper-left outer corner of the window.
  2436.      * This means that we need to adjust for the additional title height as
  2437.      * well as for any border width changes that we decide to allow.  The
  2438.      * current window gravity is to be used in computing the adjustments, just
  2439.      * as when initially locating the window.  Note that if we do decide to 
  2440.      * allow border width changes, we will need to send the synthetic 
  2441.      * ConfigureNotify event.
  2442.      */
  2443.     GetGravityOffsets (Tmp_win, &gravx, &gravy);
  2444.  
  2445.     if (cre->value_mask & CWBorderWidth) {
  2446.     int bwdelta = cre->border_width - Tmp_win->old_bw;  /* posit growth */
  2447.     if (bwdelta && Scr->ClientBorderWidth) {  /* if change allowed */
  2448.         x += gravx * bwdelta;    /* change default values only */
  2449.         y += gravy * bwdelta;    /* ditto */
  2450.         bw = cre->border_width;
  2451.         if (Tmp_win->title_height) height += bwdelta;
  2452.         x += (gravx < 0) ? bwdelta : -bwdelta;
  2453.         y += (gravy < 0) ? bwdelta : -bwdelta;
  2454.     }
  2455.     Tmp_win->old_bw = cre->border_width;  /* for restoring */
  2456.     }
  2457.  
  2458.     if (cre->value_mask & CWX) {    /* override even if border change */
  2459.     x = cre->x - bw;
  2460.     }
  2461.     if (cre->value_mask & CWY) {
  2462.     y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
  2463.     }
  2464.  
  2465.     if (cre->value_mask & CWWidth) {
  2466.     width = cre->width;
  2467.     }
  2468.     if (cre->value_mask & CWHeight) {
  2469.     height = cre->height + Tmp_win->title_height;
  2470.     }
  2471.  
  2472.     if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
  2473.     Tmp_win->zoomed = ZOOM_NONE;
  2474.  
  2475.     /*
  2476.      * SetupWindow (x,y) are the location of the upper-left outer corner and
  2477.      * are passed directly to XMoveResizeWindow (frame).  The (width,height)
  2478.      * are the inner size of the frame.  The inner width is the same as the 
  2479.      * requested client window width; the inner height is the same as the
  2480.      * requested client window height plus any title bar slop.
  2481.      */
  2482.     SetupWindow (Tmp_win, x, y, width, height, bw);
  2483. }
  2484.  
  2485.  
  2486.  
  2487. /***********************************************************************
  2488.  *
  2489.  *  Procedure:
  2490.  *    HandleShapeNotify - shape notification event handler
  2491.  *
  2492.  ***********************************************************************
  2493.  */
  2494. void
  2495. HandleShapeNotify ()
  2496. {
  2497.     XShapeEvent        *sev = (XShapeEvent *) &Event;
  2498.  
  2499. #ifdef DEBUG_EVENTS
  2500.     printf("HandleShapeNotify()\n");
  2501. #endif
  2502.     if (Tmp_win == NULL)
  2503.     return;
  2504.     if (sev->kind != ShapeBounding)
  2505.     return;
  2506.     if (!Tmp_win->wShaped && sev->shaped) {
  2507.     XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
  2508.                ShapeSet);
  2509.     }
  2510.     Tmp_win->wShaped = sev->shaped;
  2511.     SetFrameShape (Tmp_win);
  2512. }
  2513.  
  2514.  
  2515.  
  2516. /***********************************************************************
  2517.  *
  2518.  *  Procedure:
  2519.  *    HandleUnknown - unknown event handler
  2520.  *
  2521.  ***********************************************************************
  2522.  */
  2523.  
  2524. void
  2525. HandleUnknown()
  2526. {
  2527. #ifdef DEBUG_EVENTS
  2528.     fprintf(stderr, "type = %d\n", Event.type);
  2529. #endif
  2530. }
  2531.  
  2532.  
  2533.  
  2534. /***********************************************************************
  2535.  *
  2536.  *  Procedure:
  2537.  *    Transient - checks to see if the window is a transient
  2538.  *
  2539.  *  Returned Value:
  2540.  *    TRUE    - window is a transient
  2541.  *    FALSE    - window is not a transient
  2542.  *
  2543.  *  Inputs:
  2544.  *    w    - the window to check
  2545.  *
  2546.  ***********************************************************************
  2547.  */
  2548.  
  2549. int
  2550. Transient(w, propw)
  2551.     Window w, *propw;
  2552. {
  2553. #ifdef DEBUG_EVENTS
  2554.     printf("Transient()\n");
  2555. #endif
  2556.     return (XGetTransientForHint(dpy, w, propw));
  2557. }
  2558.  
  2559.  
  2560.  
  2561. /***********************************************************************
  2562.  *
  2563.  *  Procedure:
  2564.  *    FindScreenInfo - get ScreenInfo struct associated with a given window
  2565.  *
  2566.  *  Returned Value:
  2567.  *    ScreenInfo struct
  2568.  *
  2569.  *  Inputs:
  2570.  *    w    - the window
  2571.  *
  2572.  ***********************************************************************
  2573.  */
  2574.  
  2575. ScreenInfo *
  2576. FindScreenInfo(w)
  2577.     Window w;
  2578. {
  2579.     XWindowAttributes attr;
  2580.     int scrnum;
  2581.  
  2582. #ifdef DEBUG_EVENTS
  2583.     printf("FindScreenInfo()\n");
  2584. #endif
  2585.     attr.screen = NULL;
  2586.     if (XGetWindowAttributes(dpy, w, &attr)) {
  2587.     for (scrnum = 0; scrnum < NumScreens; scrnum++) {
  2588.         if (ScreenList[scrnum] != NULL &&
  2589.         (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
  2590.          attr.screen))
  2591.           return ScreenList[scrnum];
  2592.     }
  2593.     }
  2594.  
  2595.     return NULL;
  2596. }
  2597.  
  2598.  
  2599.  
  2600. static void flush_expose (w)
  2601.     Window w;
  2602. {
  2603.     XEvent dummy;
  2604.  
  2605. #ifdef DEBUG_EVENTS
  2606.     printf("flush_expose()\n");
  2607. #endif
  2608.                 /* SUPPRESS 530 */
  2609.     while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
  2610. }
  2611.  
  2612.  
  2613.  
  2614. /***********************************************************************
  2615.  *
  2616.  *  Procedure:
  2617.  *    InstallWindowColormaps - install the colormaps for one twm window
  2618.  *
  2619.  *  Inputs:
  2620.  *    type    - type of event that caused the installation
  2621.  *    tmp    - for a subset of event types, the address of the
  2622.  *          window structure, whose colormaps are to be installed.
  2623.  *
  2624.  ***********************************************************************
  2625.  */
  2626.  
  2627. InstallWindowColormaps (type, tmp)
  2628.     int type;
  2629.     TwmWindow *tmp;
  2630. {
  2631.     int i, j, n, number_cwins, state;
  2632.     ColormapWindow **cwins, *cwin, **maxcwin = NULL;
  2633.     TwmColormap *cmap;
  2634.     char *row, *scoreboard;
  2635.  
  2636. #ifdef DEBUG_EVENTS
  2637.     printf("InstallWindowColormaps()\n");
  2638. #endif
  2639.     switch (type) {
  2640.     case EnterNotify:
  2641.     case LeaveNotify:
  2642.     case DestroyNotify:
  2643.     default:
  2644.     /* Save the colormap to be loaded for when force loading of
  2645.      * root colormap(s) ends.
  2646.      */
  2647.     Scr->cmapInfo.pushed_window = tmp;
  2648.     /* Don't load any new colormap if root colormap(s) has been
  2649.      * force loaded.
  2650.      */
  2651.     if (Scr->cmapInfo.root_pushes)
  2652.         return;
  2653.     /* Don't reload the currend window colormap list.
  2654.      */
  2655.     if (Scr->cmapInfo.cmaps == &tmp->cmaps)
  2656.         return;
  2657.     if (Scr->cmapInfo.cmaps)
  2658.         for (i = Scr->cmapInfo.cmaps->number_cwins,
  2659.          cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
  2660.         (*cwins)->colormap->state &= ~CM_INSTALLABLE;
  2661.     Scr->cmapInfo.cmaps = &tmp->cmaps;
  2662.     break;
  2663.     
  2664.     case PropertyNotify:
  2665.     case VisibilityNotify:
  2666.     case ColormapNotify:
  2667.     break;
  2668.     }
  2669.  
  2670.     number_cwins = Scr->cmapInfo.cmaps->number_cwins;
  2671.     cwins = Scr->cmapInfo.cmaps->cwins;
  2672.     scoreboard = Scr->cmapInfo.cmaps->scoreboard;
  2673.  
  2674.     ColortableThrashing = FALSE; /* in case installation aborted */
  2675.  
  2676.     state = CM_INSTALLED;
  2677.  
  2678.       for (i = n = 0; i < number_cwins; i++) {
  2679.     cwin = cwins[i];
  2680.     cmap = cwin->colormap;
  2681.     cmap->state |= CM_INSTALLABLE;
  2682.     cmap->state &= ~CM_INSTALL;
  2683.     cmap->w = cwin->w;
  2684.       }
  2685.       for (i = n = 0; i < number_cwins; i++) {
  2686.       cwin = cwins[i];
  2687.       cmap = cwin->colormap;
  2688.     if (cwin->visibility != VisibilityFullyObscured &&
  2689.         n < Scr->cmapInfo.maxCmaps) {
  2690.         row = scoreboard + (i*(i-1)/2);
  2691.         for (j = 0; j < i; j++)
  2692.         if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
  2693.             break;
  2694.         if (j != i)
  2695.         continue;
  2696.         n++;
  2697.         maxcwin = &cwins[i];
  2698.         state &= (cmap->state & CM_INSTALLED);
  2699.         cmap->state |= CM_INSTALL;
  2700.     }
  2701.     }
  2702.  
  2703.     Scr->cmapInfo.first_req = NextRequest(dpy);
  2704.  
  2705.     for ( ; n > 0; maxcwin--) {
  2706.     cmap = (*maxcwin)->colormap;
  2707.     if (cmap->state & CM_INSTALL) {
  2708.         cmap->state &= ~CM_INSTALL;
  2709.         if (!(state & CM_INSTALLED)) {
  2710.         cmap->install_req = NextRequest(dpy);
  2711.         XInstallColormap(dpy, cmap->c);
  2712.         }
  2713.         cmap->state |= CM_INSTALLED;
  2714.         n--;
  2715.     }
  2716.     }
  2717. }
  2718.  
  2719.  
  2720.  
  2721. /***********************************************************************
  2722.  *
  2723.  *  Procedures:
  2724.  *    <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
  2725.  *
  2726.  *       These matching routines provide a mechanism to insure that
  2727.  *       the root colormap(s) is installed during operations like
  2728.  *       rubber banding or menu display that require colors from
  2729.  *       that colormap.  Calls may be nested arbitrarily deeply,
  2730.  *       as long as there is one UninstallRootColormap call per
  2731.  *       InstallRootColormap call.
  2732.  *
  2733.  *       The final UninstallRootColormap will cause the colormap list
  2734.  *       which would otherwise have be loaded to be loaded, unless
  2735.  *       Enter or Leave Notify events are queued, indicating some
  2736.  *       other colormap list would potentially be loaded anyway.
  2737.  ***********************************************************************
  2738.  */
  2739.  
  2740. InstallRootColormap()
  2741. {
  2742.     TwmWindow *tmp;
  2743. #ifdef DEBUG_EVENTS
  2744.     printf("InstallRootColormap()\n");
  2745. #endif
  2746.     if (Scr->cmapInfo.root_pushes == 0) {
  2747.     /*
  2748.      * The saving and restoring of cmapInfo.pushed_window here
  2749.      * is a slimy way to remember the actual pushed list and
  2750.      * not that of the root window.
  2751.      */
  2752.     tmp = Scr->cmapInfo.pushed_window;
  2753.     InstallWindowColormaps(0, &Scr->TwmRoot);
  2754.     Scr->cmapInfo.pushed_window = tmp;
  2755.     }
  2756.     Scr->cmapInfo.root_pushes++;
  2757. }
  2758.  
  2759.  
  2760.  
  2761. /* ARGSUSED*/
  2762. static Bool
  2763. UninstallRootColormapQScanner(dpy, ev, args)
  2764.     Display *dpy;
  2765.     XEvent *ev;
  2766.     char *args;
  2767. {
  2768. #ifdef DEBUG_EVENTS
  2769.     printf("UninstallRootColormapQScanner()\n");
  2770. #endif
  2771.     if (!*args)
  2772.     if (ev->type == EnterNotify) {
  2773.         if (ev->xcrossing.mode != NotifyGrab)
  2774.         *args = 1;
  2775.     } else if (ev->type == LeaveNotify) {
  2776.         if (ev->xcrossing.mode == NotifyNormal)
  2777.         *args = 1;
  2778.     }
  2779.  
  2780.     return (False);
  2781. }
  2782.  
  2783.  
  2784.  
  2785. UninstallRootColormap()
  2786. {
  2787.     char args;
  2788.     XEvent dummy;
  2789.  
  2790. #ifdef DEBUG_EVENTS
  2791.     printf("UninstallRootColormap()\n");
  2792. #endif
  2793.     if (Scr->cmapInfo.root_pushes)
  2794.     Scr->cmapInfo.root_pushes--;
  2795.     
  2796.     if (!Scr->cmapInfo.root_pushes) {
  2797.     /*
  2798.      * If we have subsequent Enter or Leave Notify events,
  2799.      * we can skip the reload of pushed colormaps.
  2800.      */
  2801.     XSync (dpy, 0);
  2802.     args = 0;
  2803.     (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
  2804.  
  2805.     if (!args)
  2806.         InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
  2807.     }
  2808. }
  2809.  
  2810. #ifdef TRACE
  2811. dumpevent (e)
  2812.     XEvent *e;
  2813. {
  2814.     char *name = NULL;
  2815.  
  2816.     switch (e->type) {
  2817.       case KeyPress:  name = "KeyPress"; break;
  2818.       case KeyRelease:  name = "KeyRelease"; break;
  2819.       case ButtonPress:  name = "ButtonPress"; break;
  2820.       case ButtonRelease:  name = "ButtonRelease"; break;
  2821.       case MotionNotify:  name = "MotionNotify"; break;
  2822.       case EnterNotify:  name = "EnterNotify"; break;
  2823.       case LeaveNotify:  name = "LeaveNotify"; break;
  2824.       case FocusIn:  name = "FocusIn"; break;
  2825.       case FocusOut:  name = "FocusOut"; break;
  2826.       case KeymapNotify:  name = "KeymapNotify"; break;
  2827.       case Expose:  name = "Expose"; break;
  2828.       case GraphicsExpose:  name = "GraphicsExpose"; break;
  2829.       case NoExpose:  name = "NoExpose"; break;
  2830.       case VisibilityNotify:  name = "VisibilityNotify"; break;
  2831.       case CreateNotify:  name = "CreateNotify"; break;
  2832.       case DestroyNotify:  name = "DestroyNotify"; break;
  2833.       case UnmapNotify:  name = "UnmapNotify"; break;
  2834.       case MapNotify:  name = "MapNotify"; break;
  2835.       case MapRequest:  name = "MapRequest"; break;
  2836.       case ReparentNotify:  name = "ReparentNotify"; break;
  2837.       case ConfigureNotify:  name = "ConfigureNotify"; break;
  2838.       case ConfigureRequest:  name = "ConfigureRequest"; break;
  2839.       case GravityNotify:  name = "GravityNotify"; break;
  2840.       case ResizeRequest:  name = "ResizeRequest"; break;
  2841.       case CirculateNotify:  name = "CirculateNotify"; break;
  2842.       case CirculateRequest:  name = "CirculateRequest"; break;
  2843.       case PropertyNotify:  name = "PropertyNotify"; break;
  2844.       case SelectionClear:  name = "SelectionClear"; break;
  2845.       case SelectionRequest:  name = "SelectionRequest"; break;
  2846.       case SelectionNotify:  name = "SelectionNotify"; break;
  2847.       case ColormapNotify:  name = "ColormapNotify"; break;
  2848.       case ClientMessage:  name = "ClientMessage"; break;
  2849.       case MappingNotify:  name = "MappingNotify"; break;
  2850.     }
  2851.  
  2852.     if (name) {
  2853.     printf ("event:  %s, %d remaining\n", name, QLength(dpy));
  2854.     } else {
  2855.     printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
  2856.     }
  2857. }
  2858. #endif /* TRACE */
  2859.  
  2860.